/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.rbac.controller.grant;

import com.alibaba.fastjson2.JSONArray;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.je.common.base.DynaBean;
import com.je.common.base.mvc.AbstractPlatformController;
import com.je.common.base.result.BaseRespResult;
import com.je.core.entity.extjs.JSONTreeNode;
import com.je.rbac.annotation.ControllerAuditLog;
import com.je.rbac.cache.FuncPermissionCache;
import com.je.rbac.exception.AccountException;
import com.je.rbac.exception.RoleException;
import com.je.rbac.service.grant.RbacGrantFuncPermissionService;
import com.je.rbac.service.grant.RbacGrantMenuPermissionService;
import com.je.rbac.service.grant.role.RbacGrantRoleService;
import com.je.rbac.service.permission.GrantTypeEnum;
import com.je.rbac.service.permission.PermissionLoadService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 角色授权
 */
@RestController
@RequestMapping(value = "/je/rbac/cloud/grant/role")
public class RbacGrantRoleController extends AbstractPlatformController {

    private static final Logger logger = LoggerFactory.getLogger(RbacGrantRoleController.class);

    @Autowired
    private RbacGrantRoleService rbacGrantRoleService;
    @Autowired
    private RbacGrantMenuPermissionService rbacGrantMenuPermissionService;
    @Autowired
    private RbacGrantFuncPermissionService rbacGrantFuncPermissionService;
    @Autowired
    private FuncPermissionCache funcPermissionCache;
    @Autowired
    private PermissionLoadService permissionLoadService;

    /**
     * 添加角色分类
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/addFolder"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "addRoleFolder",operateTypeName = "添加角色文件夹",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult addRoleModule(HttpServletRequest request) {
        String folderName = getStringParameter(request, "folderName");
        String remark = getStringParameter(request, "remark");
        String iconCls = getStringParameter(request, "icon");
        if (Strings.isNullOrEmpty(folderName)) {
            return BaseRespResult.errorResult("角色分类名称不能为空！");
        }
        DynaBean folderBean = rbacGrantRoleService.insertFolder(folderName, iconCls, remark, false);
        return BaseRespResult.successResult(folderBean, "添加角色分类成功！");
    }

    /**
     * 更新角色分类
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/updateFolder"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "updateRoleFolder",operateTypeName = "更新角色文件夹",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult updateFolder(HttpServletRequest request) {
        String folderId = getStringParameter(request, "folderId");
        String folderName = getStringParameter(request, "folderName");
        if (Strings.isNullOrEmpty(folderId)) {
            return BaseRespResult.errorResult("请选择需要更新的角色分类！");
        }
        if (Strings.isNullOrEmpty(folderName)) {
            return BaseRespResult.errorResult("角色分类名称不能为空！");
        }
        rbacGrantRoleService.updateFolder(folderId, folderName);
        return BaseRespResult.successResult("更新成功！");
    }

    /**
     * 删除角色分类
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/removeFolder"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "removeRoleFolder",operateTypeName = "移除角色文件夹",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult removeFolder(HttpServletRequest request) {
        String folderId = getStringParameter(request, "folderId");
        if (Strings.isNullOrEmpty(folderId)) {
            return BaseRespResult.errorResult("请选择需要删除的角色分类！");
        }
        try {
            rbacGrantRoleService.removeFolder(folderId);
        } catch (RoleException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }
        return BaseRespResult.successResult("删除成功！");
    }

    /**
     * 添加角色
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/addRole"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "addRole",operateTypeName = "添加角色",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult addRole(HttpServletRequest request) {
        String parentId = getStringParameter(request, "parentId");
        String roleName = getStringParameter(request, "roleName");
        String baseRoleId = getStringParameter(request, "baseRoleId");
        String remark = getStringParameter(request, "remark");
        String iconCls = getStringParameter(request, "icon");
        String permGroupIds = getStringParameter(request, "permGroupIds");
        String permGroupNames = getStringParameter(request, "permGroupNames");

        if (Strings.isNullOrEmpty(roleName)) {
            return BaseRespResult.errorResult("角色名称不能为空！");
        }

        try {
            return BaseRespResult.successResult(rbacGrantRoleService.insertRole(parentId, roleName, permGroupIds, permGroupNames, baseRoleId, iconCls, remark, false), "添加角色成功！");
        } catch (RoleException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }
    }

    /**
     * 更新角色
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/updateRole"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "updateRole",operateTypeName = "更新角色",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult updateRole(HttpServletRequest request) {
        String roleId = getStringParameter(request, "roleId");
        String roleName = getStringParameter(request, "roleName");
        String baseRoleId = getStringParameter(request, "baseRoleId");
        String remark = getStringParameter(request, "remark");
        String permGroupIds = getStringParameter(request, "permGroupIds");
        String permGroupNames = getStringParameter(request, "permGroupNames");

        if (Strings.isNullOrEmpty(roleId)) {
            return BaseRespResult.errorResult("请选择要更新的角色！");
        }

        if (Strings.isNullOrEmpty(roleName)) {
            return BaseRespResult.errorResult("角色名称不能为空！");
        }

        try {
            rbacGrantRoleService.updateRole(roleId, roleName, permGroupIds, permGroupNames, baseRoleId, remark);
        } catch (RoleException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }

        return BaseRespResult.successResult("更新成功！");
    }

    /**
     * 删除角色
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/removeRole"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "removeRole",operateTypeName = "删除角色",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult removeRole(HttpServletRequest request) {
        String roleId = getStringParameter(request, "roleId");
        if (Strings.isNullOrEmpty(roleId)) {
            return BaseRespResult.errorResult("请选择需要删除的角色！");
        }
        try {
            rbacGrantRoleService.removeRole(roleId);
        } catch (RoleException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }
        return BaseRespResult.successResult("删除成功！");
    }

    /**
     * 移动角色
     *
     * @param request
     * @return
     */
//    @AuthCheckPermission(value = {"pc-plugin-JE_CORE_RBAC-show"})
    @RequestMapping(value = {"/moveRole"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "moveRole",operateTypeName = "移动角色/文件夹",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult moveRole(HttpServletRequest request) {
        String roleId = getStringParameter(request, "roleId");
        String targetId = getStringParameter(request, "targetId");
        String order = getStringParameter(request, "order");

        if (Strings.isNullOrEmpty(roleId)) {
            return BaseRespResult.errorResult("请选择要移动的角色！");
        }

        if (Strings.isNullOrEmpty(targetId)) {
            return BaseRespResult.errorResult("请选择目标角色或角色分类！");
        }

        try {
            rbacGrantRoleService.move(roleId, targetId, Strings.isNullOrEmpty(order) ? null : Integer.valueOf(order), false);
        } catch (RoleException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }

        return BaseRespResult.successResult("移动成功！");
    }

    /**
     * 加载角色树
     *
     * @param request
     * @return
     */
//    @AuthCheckPermission(value = {"pc-plugin-JE_CORE_RBAC-show"})
    @RequestMapping(value = {"/loadRoleTree"}, method = RequestMethod.GET, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "loadRoleTree",operateTypeName = "加载角色树",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult loadRoleTree(HttpServletRequest request) {
        String refresh = getStringParameter(request, "refresh");
        //清空缓存并重新加载
        if ("1".equals(refresh)) {
            funcPermissionCache.clear();
            permissionLoadService.reloadAllRolePermCache(false);
        }

        //加载权限树逻辑
        String parentIds = getStringParameter(request, "parentIds");
        String[] parentIdArray = null;
        if (!Strings.isNullOrEmpty(parentIds)) {
            parentIdArray = parentIds.split(",");
        }
        long time = System.currentTimeMillis();
        JSONTreeNode rootNode = rbacGrantRoleService.buildRoleTree(false, parentIdArray);
        logger.info("加载授权角色树耗时：" + (System.currentTimeMillis() - time));
        return BaseRespResult.successResult(rootNode);
    }


    @RequestMapping(value = {"/importAccountUserSysOrderIdex"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult importAccountUserSysOrderIdex(HttpServletRequest request) {
        String roleId = getStringParameter(request, "roleId");
        String addStrData = getStringParameter(request, "addStrData");

        if (Strings.isNullOrEmpty(roleId)) {
            return BaseRespResult.errorResult("请选择要使用的角色！");
        }
        try {
            rbacGrantRoleService.importAccountUserSysOrderIdex(roleId, addStrData);
        } catch (AccountException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }
        return BaseRespResult.successResult("导入成功！");
    }

    /**
     * 按照人员导入账号
     *
     * @param request
     * @return
     */
    @RequestMapping(value = {"/importAccountUserByDepartmentUsers"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "importAccountByDepartmentUser",operateTypeName = "按照部门人员导入账号",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult importAccountUserByDepartmentUsers(HttpServletRequest request) {
        String roleId = getStringParameter(request, "roleId");
        String addStrData = getStringParameter(request, "addStrData");
        String deleteStrData = getStringParameter(request, "deleteStrData");

        if (Strings.isNullOrEmpty(roleId)) {
            return BaseRespResult.errorResult("请选择要使用的角色！");
        }

        if (Strings.isNullOrEmpty(addStrData) && Strings.isNullOrEmpty(deleteStrData)) {
            return BaseRespResult.errorResult("请选择部门和人员！");
        }

        try {
            rbacGrantRoleService.importAccountByUsers(roleId, addStrData);
            rbacGrantRoleService.removeAccountByUsers(roleId, deleteStrData);
        } catch (AccountException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }

        return BaseRespResult.successResult("导入成功！");
    }

    /**
     * 按照账号部门导入账号部门角色表
     *
     * @param request
     * @return
     */
//    @AuthCheckPermission(value = {"pc-plugin-JE_CORE_RBAC-show"})
    @RequestMapping(value = {"/importDevelopAccountDept"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult importAccountDeptByDepartmentAccount(HttpServletRequest request) {
        String roleId = getStringParameter(request, "roleId");
        String addStrData = getStringParameter(request, "addStrData");

        if (Strings.isNullOrEmpty(roleId)) {
            return BaseRespResult.errorResult("请选择要使用的角色！");
        }

        if (Strings.isNullOrEmpty(addStrData)) {
            return BaseRespResult.errorResult("请选择要使用的账号！");
        }
        try {
            rbacGrantRoleService.importAccountByAccounts(roleId, addStrData);
        } catch (AccountException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }

        return BaseRespResult.successResult("导入成功！");
    }

    /**
     * 按照部门导入账号
     *
     * @param request
     * @return
     */
//    @AuthCheckPermission(value = {"pc-plugin-JE_CORE_RBAC-show"})
    @RequestMapping(value = {"/importAccountUserByDepartment"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "importAccountByDept",operateTypeName = "按照部门导入账号",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult importAccountUserByDepartment(HttpServletRequest request) {
        String roleId = getStringParameter(request, "roleId");
        String departmentIds = getStringParameter(request, "departmentIds");

        if (Strings.isNullOrEmpty(roleId)) {
            return BaseRespResult.errorResult("请选择要使用的角色！");
        }

        if (Strings.isNullOrEmpty(departmentIds)) {
            return BaseRespResult.errorResult("请选择要导入的部门！");
        }

        try {
            rbacGrantRoleService.importAccountByDepartments(roleId, departmentIds);
        } catch (AccountException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }

        return BaseRespResult.successResult("导入成功！");
    }

    /**
     * 按照机构导入账号
     *
     * @param request
     * @return
     */
//    @AuthCheckPermission(value = {"pc-plugin-JE_CORE_RBAC-show"})
    @RequestMapping(value = {"/importAccountUserByOrg"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "importAccountByOrg",operateTypeName = "按照机构导入账号",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult importAccountUserByOrg(HttpServletRequest request) {
        String roleId = getStringParameter(request, "roleId");
        String orgId = getStringParameter(request, "orgId");
        String ids = getStringParameter(request, "ids");

        if (Strings.isNullOrEmpty(roleId)) {
            return BaseRespResult.errorResult("请选择要使用的角色！");
        }

        if (Strings.isNullOrEmpty(orgId)) {
            return BaseRespResult.errorResult("请选择要导入的机构！");
        }

        if (Strings.isNullOrEmpty(ids)) {
            return BaseRespResult.errorResult("请选择要导入的机构人员！");
        }
        try {
            rbacGrantRoleService.importAccountByOrgs(roleId, orgId, ids);
        } catch (AccountException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }

        return BaseRespResult.successResult("导入成功！");
    }

    /**
     * 按照机构导入账号
     *
     * @param request
     * @return
     */
//    @AuthCheckPermission(value = {"pc-plugin-JE_CORE_RBAC-show"})
    @RequestMapping(value = {"/removeAccountRole"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "removeAccountRole",operateTypeName = "移除账号角色",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult removeAccountRole(HttpServletRequest request) {
        String roleId = getStringParameter(request, "roleId");
        String strData = getStringParameter(request, "strData");

        if (Strings.isNullOrEmpty(roleId)) {
            return BaseRespResult.errorResult("请确认要移除的账号角色");
        }

        if (Strings.isNullOrEmpty(strData)) {
            return BaseRespResult.errorResult("请选择要移除的账号");
        }
        try {
            Map<String, List<String>> accountMap = new HashMap<>();
            JSONArray array = JSONArray.parseArray(strData);
            for (int i = 0; i < array.size(); i++) {
                accountMap.put(array.getJSONObject(i).getString("departmentId"),
                        Splitter.on(",").splitToList(array.getJSONObject(i).getString("accountIds")));
            }
            rbacGrantRoleService.removeAccountRole(roleId, accountMap);
        } catch (AccountException e) {
            return BaseRespResult.errorResult(e.getMessage());
        }

        return BaseRespResult.successResult("移除成功！");
    }

    /**
     * 保存角色菜单授权
     *
     * @param request
     * @return
     */
//    @AuthCheckPermission(value = {"pc-plugin-JE_CORE_RBAC-show"})
    @RequestMapping(value = {"/saveRoleMenuPermission"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "saveRoleMenuPermission",operateTypeName = "更新角色菜单授权",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult saveMenuPermission(HttpServletRequest request) {
        String roleIds = getStringParameter(request, "roleIds");
        String addedStrData = getStringParameter(request, "addedStrData");
        String deletedStrData = getStringParameter(request, "deletedStrData");
        if (Strings.isNullOrEmpty(addedStrData) && Strings.isNullOrEmpty(deletedStrData)) {
            return BaseRespResult.errorResult("无数据操作！");
        }
        //更新权限
        rbacGrantMenuPermissionService.updateRoleMenuPermissions(GrantTypeEnum.MENU, roleIds, addedStrData, deletedStrData);
        return BaseRespResult.successResult("保存授权成功！");
    }

    /**
     * 保存功能授权
     *
     * @param request
     * @return
     */
//    @AuthCheckPermission(value = {"pc-plugin-JE_CORE_RBAC-show"})
    @RequestMapping(value = {"/saveRoleFuncPermission"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "saveRoleFuncPermission",operateTypeName = "更新角色功能授权",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult saveRoleFuncPermission(HttpServletRequest request) {
        String roleIds = getStringParameter(request, "roleIds");
        String addedStrData = getStringParameter(request, "addedStrData");
        String deletedStrData = getStringParameter(request, "deletedStrData");

        if (Strings.isNullOrEmpty(addedStrData) && Strings.isNullOrEmpty(deletedStrData)) {
            return BaseRespResult.errorResult("无数据操作！");
        }

        rbacGrantFuncPermissionService.updateRoleFuncPermissions(GrantTypeEnum.FUNC, roleIds, addedStrData, deletedStrData);
        return BaseRespResult.successResult("保存授权成功！");
    }

    /**
     * 保存APP授权
     *
     * @param request
     * @return
     */
//    @AuthCheckPermission(value = {"pc-plugin-JE_CORE_RBAC-show"})
    @RequestMapping(value = {"/saveRoleAppPermission"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "saveRoleAppPermission",operateTypeName = "更新角色APP授权",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult saveRoleAppPermission(HttpServletRequest request) {
        return BaseRespResult.errorResult("此版本不包括此功能！");
    }

    /**
     * 清理授权缓存
     *
     * @return
     */
    @RequestMapping(value = {"/clearGrantPermissions"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    @ControllerAuditLog(moduleName = "角色授权模块",operateTypeCode = "clearPermission",operateTypeName = "清除权限缓存",logTypeCode = "securityManage",logTypeName = "安全管理")
    public BaseRespResult clearGrantPermissions() {
        permissionLoadService.reloadAllPermGroupPermCache(false);
        permissionLoadService.reloadAllRolePermCache(false);
        permissionLoadService.reloadAllDevelopRolePermCache();
        permissionLoadService.reloadAllDepartmentPermCache();
        permissionLoadService.reloadAllOrgPermCache();
        permissionLoadService.reloadAllUserPermCache();
        return BaseRespResult.successResult("清理成功！");
    }

}
